﻿using System.Configuration;

namespace Exocortex.Base.Shared
{

    public class CortexConfigurationSection : ConfigurationSection
    {

        public const string SectionId = "cortexConfig";

        [ConfigurationProperty("engines", IsDefaultCollection = false)]
        [ConfigurationCollection(
            typeof(EngineConfigurationElement),
            AddItemName = "engine",
            CollectionType = ConfigurationElementCollectionType.BasicMap)]
        public EngineConfigurationCollection Engines
        {
            get
            {
                return (EngineConfigurationCollection)this["engines"];
            }
        }

        [ConfigurationProperty("eventServers", IsDefaultCollection = false)]
        [ConfigurationCollection(
            typeof(EventServerConfigurationElement),
            AddItemName = "eventServer",
            CollectionType = ConfigurationElementCollectionType.BasicMap)]
        public EventServerConfigurationCollection EventServers
        {
            get
            {
                return (EventServerConfigurationCollection)this["eventServers"];
            }
        }

        [ConfigurationProperty("scripts", IsDefaultCollection = false)]
        [ConfigurationCollection(
            typeof(EngineConfigurationElement),
            AddItemName = "script",
            CollectionType = ConfigurationElementCollectionType.BasicMap)]
        public ScriptConfigurationCollection Scripts
        {
            get
            {
                return (ScriptConfigurationCollection)this["scripts"];
            }
        }

        [ConfigurationProperty("feeds", IsDefaultCollection = false)]
        [ConfigurationCollection(
            typeof(NugetConfigurationElement),
            AddItemName = "feed",
            CollectionType = ConfigurationElementCollectionType.BasicMap)]
        public NugetConfigurationCollection Servers
        {
            get
            {
                return (NugetConfigurationCollection)this["feeds"];
            }
        }

    }

    [ConfigurationCollection(
        typeof(EngineConfigurationElement),
        AddItemName = "script",
        CollectionType = ConfigurationElementCollectionType.BasicMap)]
    public class ScriptConfigurationCollection : ConfigurationElementCollection
    {

        public ScriptConfigurationElement this[int index]
        {
            get { return (ScriptConfigurationElement)base.BaseGet(index); }
            set
            {
                if (base.BaseGet(index) != null)
                    base.BaseRemoveAt(index);
                base.BaseAdd(index, value);
            }
        }

        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.BasicMap;
            }
        }

        protected override string ElementName
        {
            get
            {
                return "script";
            }
        }

        public ScriptConfigurationElement this[string name]
        {
            get { return (ScriptConfigurationElement)base.BaseGet(name); }
        }

        public void Add(ScriptConfigurationElement engine)
        {
            base.BaseAdd(engine);
        }

        public void Remove(string name)
        {
            base.BaseRemove(name);
        }

        public void Clear()
        {
            base.BaseClear();
        }

        public void Remove(ScriptConfigurationElement engine)
        {
            base.BaseRemove(engine);
        }

        public void RemoveAt(int index)
        {
            base.BaseRemoveAt(index);
        }

        public string GetKey(int index)
        {
            return (string)base.BaseGetKey(index);
        }

        #region Overrides of ConfigurationElementCollection

        protected override ConfigurationElement CreateNewElement()
        {
            return new ScriptConfigurationElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ScriptConfigurationElement)element).Path;
        }

        #endregion
    }

    public class ScriptConfigurationElement : ConfigurationElement
    {

        public ScriptConfigurationElement() { }

        public ScriptConfigurationElement(string engine, string path)
        {
            Engine = engine;
            Path = path;
        }

        [ConfigurationProperty("engine", IsRequired = true)]
        public string Engine
        {
            get { return (string)this["engine"]; }
            set { this["engine"] = value; }
        }

        [ConfigurationProperty("path", IsRequired = true)]
        public string Path
        {
            get { return (string)this["path"]; }
            set { this["path"] = value; }
        }

    }


    [ConfigurationCollection(
        typeof(EngineConfigurationElement),
        AddItemName = "engine",
        CollectionType = ConfigurationElementCollectionType.BasicMap)]
    public class EngineConfigurationCollection : ConfigurationElementCollection
    {

        public EngineConfigurationElement this[int index]
        {
            get { return (EngineConfigurationElement)base.BaseGet(index); }
            set
            {
                if (base.BaseGet(index) != null)
                    base.BaseRemoveAt(index);
                base.BaseAdd(index, value);
            }
        }

        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.BasicMap;
            }
        }

        protected override string ElementName
        {
            get
            {
                return "engine";
            }
        }

        public EngineConfigurationElement this[string name]
        {
            get { return (EngineConfigurationElement)base.BaseGet(name); }
        }

        public void Add(EngineConfigurationElement engine)
        {
            base.BaseAdd(engine);
        }

        public void Remove(string name)
        {
            base.BaseRemove(name);
        }

        public void Clear()
        {
            base.BaseClear();
        }

        public void Remove(EngineConfigurationElement engine)
        {
            base.BaseRemove(engine);
        }

        public void RemoveAt(int index)
        {
            base.BaseRemoveAt(index);
        }

        public string GetKey(int index)
        {
            return (string)base.BaseGetKey(index);
        }

        #region Overrides of ConfigurationElementCollection

        protected override ConfigurationElement CreateNewElement()
        {
            return new EngineConfigurationElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((EngineConfigurationElement)element).Alias;
        }

        #endregion
    }

    public class EngineConfigurationElement : ConfigurationElement
    {

        public EngineConfigurationElement() { }

        public EngineConfigurationElement(string name, string address)
        {
            Alias = name;
            Address = address;
        }

        public EngineConfigurationElement(
            string alias,
            bool isDefault,
            bool autoAssemblyResolve,
            int allowedInstruction)
        {
            Alias = alias;
            IsDefault = isDefault;
            AutoAssemblyResolve = autoAssemblyResolve;
            AllowedInstructions = allowedInstruction;
        }

        [ConfigurationProperty("script", IsRequired = false)]
        public string Script
        {
            get { return (string)this["script"]; }
            set { this["script"] = value; }
        }

        [ConfigurationProperty("alias", IsRequired = true)]
        //        [StringValidator(MinLength = 1, MaxLength = 60)]
        public string Alias
        {
            get { return (string)this["alias"]; }
            set { this["alias"] = value; }
        }

        [ConfigurationProperty("address", IsRequired = false)]
        public string Address
        {
            get { return (string)this["address"]; }
            set { this["address"] = value; }
        }

        [ConfigurationProperty("isDefault", IsRequired = false, DefaultValue = false)]
        public bool IsDefault
        {
            get { return (bool)this["isDefault"]; }
            set { this["isDefault"] = value; }
        }

        [ConfigurationProperty("autoAssemblyResolve", IsRequired = false, DefaultValue = true)]
        public bool AutoAssemblyResolve
        {
            get { return (bool)this["autoAssemblyResolve"]; }
            set { this["autoAssemblyResolve"] = value; }
        }

        [ConfigurationProperty("allowedInstructions", IsRequired = false, DefaultValue = 2047)]
        public int AllowedInstructions
        {
            get { return (int)this["allowedInstructions"]; }
            set { this["allowedInstructions"] = value; }
        }

    }

    [ConfigurationCollection(
        typeof(EventServerConfigurationElement),
        AddItemName = "eventServer",
        CollectionType = ConfigurationElementCollectionType.BasicMap)]
    public class EventServerConfigurationCollection : ConfigurationElementCollection
    {

        public EventServerConfigurationElement this[int index]
        {
            get { return (EventServerConfigurationElement)base.BaseGet(index); }
            set
            {
                if (base.BaseGet(index) != null)
                    base.BaseRemoveAt(index);
                base.BaseAdd(index, value);
            }
        }

        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.BasicMap;
            }
        }

        protected override string ElementName
        {
            get
            {
                return "eventServer";
            }
        }

        public EventServerConfigurationElement this[string name]
        {
            get { return (EventServerConfigurationElement)base.BaseGet(name); }
        }

        public void Add(EventServerConfigurationElement engine)
        {
            base.BaseAdd(engine);
        }

        public void Remove(string name)
        {
            base.BaseRemove(name);
        }

        public void Clear()
        {
            base.BaseClear();
        }

        public void Remove(EventServerConfigurationElement engine)
        {
            base.BaseRemove(engine);
        }

        public void RemoveAt(int index)
        {
            base.BaseRemoveAt(index);
        }

        public string GetKey(int index)
        {
            return (string)base.BaseGetKey(index);
        }

        #region Overrides of ConfigurationElementCollection

        protected override ConfigurationElement CreateNewElement()
        {
            return new EventServerConfigurationElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((EventServerConfigurationElement)element).Alias;
        }

        #endregion
    }

    public class EventServerConfigurationElement : ConfigurationElement
    {

        public EventServerConfigurationElement() { }

        public EventServerConfigurationElement(
            string alias,
            string address,
            string httpClientServerName = null,
            int? httpPort = null,
            string identifier = null)
        {
            Alias = alias;
            Address = address;
            HttpClientServerName = httpClientServerName;
            HttpPort = httpPort;
            Identifier = identifier;
        }

        [ConfigurationProperty("alias", IsRequired = true)]
        public string Alias
        {
            get { return (string)this["alias"]; }
            set { this["alias"] = value; }
        }

        [ConfigurationProperty("address", IsRequired = true)]
        public string Address
        {
            get { return (string)this["address"]; }
            set { this["address"] = value; }
        }

        [ConfigurationProperty("httpClientServerName", IsRequired = false)]
        public string HttpClientServerName
        {
            get { return (string)this["httpClientServerName"]; }
            set { this["httpClientServerName"] = value; }
        }

        [ConfigurationProperty("httpPort", IsRequired = false)]
        public int? HttpPort
        {
            get { return (int?)this["httpPort"]; }
            set { this["httpPort"] = value; }
        }

        [ConfigurationProperty("identifier", IsRequired = false)]
        public string Identifier
        {
            get { return (string)this["identifier"]; }
            set { this["identifier"] = value; }
        }

    }

    [ConfigurationCollection(
        typeof(NugetConfigurationElement),
        AddItemName = "feed",
        CollectionType = ConfigurationElementCollectionType.BasicMap)]
    public class NugetConfigurationCollection : ConfigurationElementCollection
    {

        public NugetConfigurationElement this[int index]
        {
            get { return (NugetConfigurationElement)base.BaseGet(index); }
            set
            {
                if (base.BaseGet(index) != null)
                    base.BaseRemoveAt(index);
                base.BaseAdd(index, value);
            }
        }

        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.BasicMap;
            }
        }

        protected override string ElementName
        {
            get
            {
                return "feed";
            }
        }

        public NugetConfigurationElement this[string name]
        {
            get { return (NugetConfigurationElement)base.BaseGet(name); }
        }

        public void Add(NugetConfigurationElement engine)
        {
            base.BaseAdd(engine);
        }

        public void Remove(string name)
        {
            base.BaseRemove(name);
        }

        public void Clear()
        {
            base.BaseClear();
        }

        public void Remove(NugetConfigurationElement engine)
        {
            base.BaseRemove(engine);
        }

        public void RemoveAt(int index)
        {
            base.BaseRemoveAt(index);
        }

        public string GetKey(int index)
        {
            return (string)base.BaseGetKey(index);
        }

        #region Overrides of ConfigurationElementCollection

        protected override ConfigurationElement CreateNewElement()
        {
            return new NugetConfigurationElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((NugetConfigurationElement)element).Alias;
        }

        #endregion
    }

    public class NugetConfigurationElement : ConfigurationElement
    {

        public NugetConfigurationElement() { }

        public NugetConfigurationElement(string name, string address, bool isDefault = false)
        {
            Alias = name;
            Address = address;
            IsDefault = isDefault;
        }

        [ConfigurationProperty("alias", IsRequired = true)]
        public string Alias
        {
            get { return (string)this["alias"]; }
            set { this["alias"] = value; }
        }

        [ConfigurationProperty("address", IsRequired = true)]
        public string Address
        {
            get { return (string)this["address"]; }
            set { this["address"] = value; }
        }

        [ConfigurationProperty("isDefault", IsRequired = false)]
        public bool IsDefault
        {
            get { return (bool)this["isDefault"]; }
            set { this["isDefault"] = value; }
        }

    }

}
